package FileBrowser;

import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.io.file.FileSystemListener;
import javax.microedition.io.file.FileSystemRegistry;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import sUtils.*;

/**
 * Demonstration MIDlet for File Connection API. This MIDlet implements simple
 * file browser for the filesystem available to the J2ME applications.
 */
public class FileBrowser extends MIDlet implements CommandListener, FileSystemListener {
    private static final String[] typeListDE = {"Datei", "Verzeichnis"};
    private static final String[] monthListDE =
        {"Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"};
    
    private static final String[] typeList = {"File", "Folder"};
    private static final String[] monthList =
        {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

    /* special string denotes upper directory */
    private static final String UP_DIRECTORY = "..";

    /* special string that denotes upper directory accessible by this browser.
     * this virtual directory contains all roots.
     */
    private static final String MEGA_ROOT = "/";

    /* separator string as defined by FC specification */
    private static final String SEP_STR = "/";

    /* separator character as defined by FC specification */
    private static final char SEP = '/';
    private String currDirName;
    private Command view;
    private Command creat;

    //add delete file functionality
    private Command delete;
    private Command creatOK;
    private Command prop;
    private Command back;
    private Command lock;
    private Command exit;
    private TextField nameInput; // Input field for new file name
    private ChoiceGroup typeInput; // Input field for file type (regular/dir)
    private Image dirIcon;
    private Image fileIcon;
    private Image videoIcon;
    private Image photoIcon;
    private Image musicIcon;
    private Image yesIcon;
    private Image noIcon;
    private Image[] iconList;
    private List list;
            boolean listEnabled;
    private MediaBrowser currPlayer2;
    private MediaPlayer mainPlayer;
    private java.util.Vector videos, music, photos;
    private Form waitForm;

   boolean isPhoto( String check )
    {
        return (check.endsWith(".jpg")||check.endsWith(".png")
                ||check.endsWith(".gif")||check.endsWith(".bmp")||check.endsWith(".tif"));
    }

    boolean isMusic( String check )
    {
        return check.endsWith(".wav")||check.endsWith(".mp3")||check.endsWith(".mid")||check.endsWith(".amr");
    }

    boolean isVideo( String check )
    {
        return (check.endsWith(".mp4") || 
                check.endsWith(".mpg") || check.endsWith(".3gp") ||
                check.endsWith(".avi") || check.endsWith(".wmv") || check.endsWith(".divx"));
    }

     public FileBrowser () {

        Lang.init();
        view = new Command (Lang.word("View","Anzeigen"), Command.ITEM, 1);
        creat = new Command (Lang.word("Create", "Neu"), Command.ITEM, 2);
        delete = new Command (Lang.word("Delete","Löschen"), Command.ITEM, 3);
        creatOK = new Command ("OK", Command.OK, 1);
        prop = new Command (Lang.word("Properties","Eigenschaften"), Command.ITEM, 2);
        back = new Command (Lang.word("Back","Zurück"), Command.EXIT, 2);
        lock = new Command ("Lock", Command.OK, 2);
        exit = new Command (Lang.word("Quit","Beenden"), Command.ITEM, 5);


        currPlayer2 = null;
        currDirName = MEGA_ROOT;
        listEnabled = false;
        mainPlayer = new MediaPlayer(this);

        try { dirIcon = Image.createImage ("/icons/dir.png"); } catch (IOException e) {
            dirIcon = null;
        }

        try { fileIcon = Image.createImage ("/icons/file.png"); } catch (IOException e) {
            fileIcon = null;
        }

        try { yesIcon = Image.createImage ("/icons/yes.png"); }  catch (IOException e) {
            yesIcon = null;
        }

        try { noIcon = Image.createImage ("/icons/no.png"); } catch (IOException e) {
            noIcon = null;
        }

        try { photoIcon = Image.createImage ("/icons/photo.png"); } catch (IOException e) {
           photoIcon = null;
        }
        try { videoIcon = Image.createImage ("/icons/video.png"); } catch (IOException e) {
           videoIcon = null;
        }
        try { musicIcon = Image.createImage ("/icons/music.png"); } catch (IOException e) {
           musicIcon = null;
        }

        waitForm = new Form (Lang.word("Wait...","Warte..."));

        iconList = new Image[] {fileIcon, dirIcon};
        FileSystemRegistry.addFileSystemListener (this);
    }

    public void startApp () {
        try {
            showCurrDirNow ();
        }
        catch (SecurityException e) {
            Alert alert =
                new Alert (
                    "Error", "You are not authorized to access the restricted API", null,
                    AlertType.ERROR);
            alert.setTimeout (Alert.FOREVER);

            Form form = new Form ("Cannot access FileConnection");
            form.append (
                new StringItem (
                    null,
                    "You cannot run this MIDlet with the current permissions. " +
                        "Sign the MIDlet suite, or run it in a different security domain"));
            form.addCommand (exit);
            form.setCommandListener (this);
            Display.getDisplay (this).setCurrent (alert, form);
        }
        catch (Exception e) {
            e.printStackTrace ();
        }
    }

    public void pauseApp () {
    }

    public void destroyApp (boolean cond) {
        FileSystemRegistry.removeFileSystemListener (this);
        notifyDestroyed ();
    }

    public void commandAction (Command c, Displayable d) {
        if (c == view) {
            Display.getDisplay (this).setCurrent (waitForm);
            listEnabled = false;
            list = (List) d;
            final String currFile = list.getString (list.getSelectedIndex ());
            new Thread (
                new Runnable() {
                    public void run () {
                        if (currFile.endsWith (SEP_STR) || currFile.equals (UP_DIRECTORY)) {
                            traverseDirectory (currFile);
                        }
                        else {
                            // Show file contents
                            showFile (currFile);

                        }
                    }
                }).start ();

        }
        else if (c == prop) {
            list = (List) d;
            String currFile = list.getString (list.getSelectedIndex ());

            showProperties (currFile);
        }
        else if (c == creat) {
            createFile ();
        }
        else if (c == creatOK) {
            String newName = nameInput.getString ();

            if ((newName == null) || newName.equals ("")) {
                Alert alert =
                    new Alert (
                        "Error!", "File Name is empty. Please provide file name", null,
                        AlertType.ERROR);
                alert.setTimeout (Alert.FOREVER);
                Display.getDisplay (this).setCurrent (alert);
            }
            else {
                // Create file in a separate thread and disable all commands
                // except for "exit"
                executeCreateFile (newName, typeInput.getSelectedIndex () != 0);
                Display.getDisplay (this).getCurrent ().removeCommand (creatOK);
                Display.getDisplay (this).getCurrent ().removeCommand (back);
            }
        }
        else if (c == back) {
            listEnabled = true;
            if (currPlayer2!=null) {
                currPlayer2.close();
            //CLOSE    mainPlayer.close();
                currPlayer2=null;
                if (list!=null) Display.getDisplay(this).setCurrent(list); else showCurrDir ();
            }
            else
                if (Display.getDisplay(this).getCurrent()==list) traverseDirectory (UP_DIRECTORY); else showCurrDir ();
        }
        else if (c == lock) {
            mainPlayer.setScreenSaver();
        }
        else if (c == exit) {
            if (currPlayer2!=null) {
                currPlayer2.close();
            //CLOSE    mainPlayer.close();
                currPlayer2=null;
            }
            destroyApp (false);
        }
        else if (c == delete) {
            List curr = (List) d;
            String currFile = curr.getString (curr.getSelectedIndex ());
            executeDelete (currFile);
        }
    }

    void delete (String currFile) {
        if (!currFile.equals (UP_DIRECTORY)) {
            if (currFile.endsWith (SEP_STR)) {
                checkDeleteFolder (currFile);
            }
            else {
                deleteFile (currFile);
                showCurrDir ();
            }
        }
        else {
            Alert cantDeleteFolder =
                new Alert (
                    "Error!",
                    "Can not delete The up-directory (..) " + "symbol! not a real folder", null,
                    AlertType.ERROR);
            cantDeleteFolder.setTimeout (Alert.FOREVER);
            Display.getDisplay (this).setCurrent (cantDeleteFolder);
        }
    }

    private void executeDelete (String currFile) {
        final String file = currFile;
        new Thread (
            new Runnable() {
                public void run () {
                    delete (file);
                }
            }).start ();
    }

    private void checkDeleteFolder (String folderName) {
        try {
            FileConnection fcdir =
                (FileConnection) Connector.open ("file://localhost/" + currDirName + folderName);
            Enumeration content = fcdir.list ("*", true);

            //only empty directory can be deleted
            if (!content.hasMoreElements ()) {
                fcdir.delete ();
                showCurrDir ();
            }
            else {
                Alert cantDeleteFolder =
                    new Alert (
                        "Error!", "Can not delete The non-empty folder: " + folderName, null,
                        AlertType.ERROR);
                cantDeleteFolder.setTimeout (Alert.FOREVER);
                Display.getDisplay (this).setCurrent (cantDeleteFolder);
            }
        }
        catch (IOException ioe) {
            System.out.println (currDirName + folderName);

            ioe.printStackTrace ();
        }
    }

    //Starts creatFile with another Thread
    private void executeCreateFile (final String name, final boolean val) {
        new Thread (
            new Runnable() {
                public void run () {
                    createFile (name, val);
                }
            }).start ();
    }

    /**
     * Show file list in the current directory. Perform the action in differrent
     * thread not tu block system calls by security questions.
     */
    void showCurrDir () {
        new Thread(new Runnable() {
            public void run() {
                showCurrDirNow();
            }
        }).start();
    }

    /**
     * Show file list in the current directory .
     */
    void showCurrDirNow () {
        Enumeration e;
        FileConnection currDir = null;

        videos = new Vector(10,5);
        music = new Vector(10,5);
        photos = new Vector(10,5);
        
        try {
            list = new List (currDirName, List.IMPLICIT);
            list.setFitPolicy(List.TEXT_WRAP_OFF);
            
            if (MEGA_ROOT.equals (currDirName)) {
                e = FileSystemRegistry.listRoots ();
            }
            else {
                currDir = (FileConnection) Connector.open ("file://localhost/" + currDirName);
                e = currDir.list("*",true);
                // not root - draw UP_DIRECTORY
                list.append(UP_DIRECTORY, dirIcon);
            }



            while (e.hasMoreElements ()) {
                String fileName = (String) e.nextElement ();

                if (fileName.charAt (fileName.length () - 1) == SEP) {
                    // This is directory
                    list.append (fileName, dirIcon);
                }
                else {
                    // this is regular file
                    String check = fileName.toLowerCase();
                    if (isMusic(check)) { list.append (fileName, musicIcon); music.addElement(new String(fileName)); } else
                    if (isPhoto(check)) { list.append (fileName, photoIcon); photos.addElement(new String(fileName)); } else
                    if (isVideo(check)) { list.append (fileName, videoIcon); videos.addElement(new String(fileName)); } else
                    list.append (fileName, fileIcon);
                }
               
            }

            list.setSelectCommand (view);
            

            //Do not allow creating files/directories beside root
            if (!MEGA_ROOT.equals (currDirName)) {
                list.addCommand (back);
                list.addCommand (prop);
                list.addCommand (creat);
                list.addCommand (delete);
            }
            else
                list.addCommand (exit);
            list.setCommandListener (this);

            if (currDir != null) {
                currDir.close ();
            }

            Display.getDisplay (this).setCurrent (list);
        }
        catch (IOException ioe) {
            ioe.printStackTrace ();
        }
    }

    void traverseDirectory (String fileName) {
        /* In case of directory just change the current directory
         * and show it
         */
        if (currDirName.equals (MEGA_ROOT)) {
            if (fileName.equals (UP_DIRECTORY)) {
                // can not go up from MEGA_ROOT
                return;
            }

            currDirName = fileName;
        }
        else if (fileName.equals (UP_DIRECTORY)) {
            // Go up one directory
            int i = currDirName.lastIndexOf (SEP, currDirName.length () - 2);

            if (i != -1) {
                currDirName = currDirName.substring (0, i + 1);
            }
            else {
                currDirName = MEGA_ROOT;
            }
        }
        else {
            currDirName = currDirName + fileName;
        }

        showCurrDir ();
    }


    void showFile (String fileName) {
        String check = fileName.toLowerCase();

        Vector v = null;
        if (isVideo(check)) v = videos; else
        if (isPhoto(check)) v = photos; else
        if (isMusic(check)) v = music;

        if (v!=null)
        {
            int c=0;
            for ( int i=0; i<v.size(); i++ )
                if (v.elementAt(i).equals(fileName)) { c=i; break; }
            try {
                currPlayer2 = new MediaBrowser(this,mainPlayer,currDirName,v,c);
                currPlayer2.addCommand (lock);
                currPlayer2.addCommand (back);
                currPlayer2.setCommandListener (this);
                Display.getDisplay(this).setCurrent(currPlayer2);
                return;
            }
            catch (Exception e) {
                    Alert alert = new Alert ( "Error!", "Canot create MediaBrowser\nException: " + e.getMessage (), null, AlertType.ERROR);
                    alert.setTimeout (Alert.FOREVER);
                    Display.getDisplay (this).setCurrent (alert);
            }
                         
        }
        try {
            String fName = "file://localhost/" + currDirName + fileName;
            FileConnection fc = (FileConnection) Connector.open (fName);
            if (!fc.exists ())
            {
                throw new IOException ("File does not exists");
            }
            InputStream is = (InputStream)fc.openInputStream();
            {
                byte[] b = new byte[16384];

                int length = is.read (b, 0, 16384);
                is.close ();
                fc.close ();

                TextBox viewer =
                    new TextBox (
                        Lang.word("View File: ","Zeige Datei: ") + fileName, null, 16384,
                        TextField.ANY | TextField.UNEDITABLE);

               // viewer.addCommand (exit);
                viewer.addCommand (back);
                viewer.setCommandListener (this);

                if (length > 0) {
                    viewer.setString (new String (b, 0, length));
                }

                Display.getDisplay (this).setCurrent (viewer);
            }
            is.close ();
            fc.close ();

        }
        catch (Exception e) {
            Alert alert =
                new Alert (
                    "Error!",
                    "Can not access file " + fileName + " in directory " + currDirName +
                        "\nException: " + e.getMessage (), null, AlertType.ERROR);
            alert.setTimeout (Alert.FOREVER);
            Display.getDisplay (this).setCurrent (alert);
        }
    }

    void deleteFile (String fileName) {
        try {
            FileConnection fc = (FileConnection) Connector.open ("file:///" + currDirName + fileName);
            fc.delete ();
        }
        catch (Exception e) {
            Alert alert =
                new Alert (
                    "Error!",
                    "Can not access/delete file " + fileName + " in directory " + currDirName +
                        "\nException: " + e.getMessage (), null, AlertType.ERROR);
            alert.setTimeout (Alert.FOREVER);
            Display.getDisplay (this).setCurrent (alert);
        }
    }

    void showProperties (String fileName) {
        try {
            if (fileName.equals (UP_DIRECTORY)) {
                return;
            }

            FileConnection fc =
                (FileConnection) Connector.open ("file:///" + currDirName + fileName);

            if (!fc.exists ()) {
                throw new IOException ("File does not exists");
            }

            Form props = new Form (Lang.word("Properties: ","Eigenschaften: ") + fileName);

            props.append (new StringItem (Lang.word("Dest:","Ort:"), currDirName));
            props.append (new StringItem (Lang.word("Type:","Typ:"),
                    fc.isDirectory () ? Lang.word("Folder","Verzeichnis") : Lang.word("File","Datei")));
            props.append (new StringItem (Lang.word("Size:","Groesse:"),
                    " "+fc.fileSize()+"B"));
            props.append (new StringItem (Lang.word("Changed:","Bearbeitet:"), myDate (fc.lastModified ())));

            props.append ("Attributes:");
            if (fc.canRead()) props.append (Lang.word(" Read "," Lesen "));
            if (fc.canWrite())props.append (Lang.word(" Write "," Schreiben "));
            if (fc.isHidden()) props.append (Lang.word(" Hidden "," Versteckt "));

            props.addCommand (back);
            props.setCommandListener (this);

            fc.close ();

            Display.getDisplay (this).setCurrent (props);
        }
        catch (Exception e) {
            Alert alert =
                new Alert (
                    "Error!",
                    "Can not access file " + fileName + " in directory " + currDirName +
                        "\nException: " + e.getMessage (), null, AlertType.ERROR);
            alert.setTimeout (Alert.FOREVER);
            Display.getDisplay (this).setCurrent (alert);
        }
    }

    void createFile () {
        Form creator = new Form (Lang.word("Create File","Neue Datei"));
        nameInput = new TextField ("Name", null, 256, TextField.ANY);
        typeInput = new ChoiceGroup (Lang.word("Type","Typ"), Choice.EXCLUSIVE, Lang.id==1 ? typeListDE : typeList, iconList);
        creator.append (nameInput);
        creator.append (typeInput);
        creator.addCommand (creatOK);
        creator.addCommand (back);
        creator.setCommandListener (this);
        Display.getDisplay (this).setCurrent (creator);
    }

    void createFile (String newName, boolean isDirectory) {
        try {
            FileConnection fc = (FileConnection) Connector.open ("file:///" + currDirName + newName);

            if (isDirectory) {
                fc.mkdir ();
            }
            else {
                fc.create ();
            }

            showCurrDir ();
        }
        catch (Exception e) {
            String s = "Fehler beim Anlegen der Datei '" + newName + "'";

            if ((e.getMessage () != null) && (e.getMessage ().length () > 0)) {
                s += ("\n" + e);
            }

            Alert alert = new Alert ("Error!", s, null, AlertType.ERROR);
            alert.setTimeout (Alert.FOREVER);
            Display.getDisplay (this).setCurrent (alert);
            // Restore the commands that were removed in commandAction()
            Display.getDisplay (this).getCurrent ().addCommand (creatOK);
            Display.getDisplay (this).getCurrent ().addCommand (back);
        }
    }

    private String myDate (long time) {
        Calendar cal = Calendar.getInstance ();

        cal.setTime (new Date (time));

        StringBuffer sb = new StringBuffer ();
        int hh = cal.get (Calendar.HOUR_OF_DAY);
        int mm = cal.get (Calendar.MINUTE);
        int ss = cal.get (Calendar.SECOND);
        int day = cal.get (Calendar.DAY_OF_MONTH);


        if (hh<10) sb.append("0"); sb.append (hh);
        sb.append (':');
        if (mm<10) sb.append("0"); sb.append (mm);
        sb.append (':');
        if (ss<10) sb.append("0"); sb.append (ss);
        sb.append (',');
        sb.append (' ');
        if (day<10) sb.append("0"); sb.append (day);
        sb.append (' ');
        sb.append (Lang.id==1 ? monthListDE[cal.get (Calendar.MONTH)] : monthList[cal.get (Calendar.MONTH)]);
        sb.append (' ');
        sb.append (cal.get (Calendar.YEAR));

        return sb.toString ();
    }

    public void rootChanged (int state, String rootName) {
        showCurrDir ();
    }
}
